package com.jerry.springcloudalibaba.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.jerry.springcloudalibaba.entity.CommonResult;
import com.jerry.springcloudalibaba.handler.MyBlockHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@RestController
@Slf4j
public class SentinelController {

    /////////////////////////////////////  服务限流方式 开始  ////////////////////////////////////////
    //按地址url限流  --  限流url：/consumer/sentinel/get
    //注意：地址限流时不能使用 blockHandler
    @GetMapping("/consumer/sentinel/get")
    @SentinelResource(value = "sentinel/get")
    public CommonResult getList() {
        return new CommonResult(200, "按url地址限流测试OK");
    }

    // 按资源名称限流  --  限流名称：sentinel/getId
    @GetMapping("/consumer/sentinel/get/{id}")
    @SentinelResource(value = "sentinel/getId", blockHandler = "handler_getId_exception")
    public CommonResult getById(@PathVariable("id") Long id) {
        return new CommonResult(200, "按资源名称限流测试OK");
    }

    public CommonResult handler_getId_exception(Long id, BlockException exception) {
        return new CommonResult(444, exception.getClass().getCanonicalName()+"\t getById()服务不可用");
    }
    /////////////////////////////////////  服务限流方式 结束  ////////////////////////////////////////

    /////////////////////////////////////  服务异常处理方式 开始  ////////////////////////////////////////

    // 同一个类中处理异常
    @GetMapping("/consumer/sentinel/get2/{id}")
    @SentinelResource(value = "sentinel/getId2", blockHandler = "handler_getId_exception")   // handler_getId_exception方法在上面
    public CommonResult getById2(@PathVariable("id") Long id) {
        return new CommonResult(200, "按资源名称限流测试OK");
    }

    // 自定义异常处理类，统一处理
    @GetMapping("/consumer/sentinel/customerHandler")
    @SentinelResource(value = "customerHandlerException",
            blockHandlerClass = MyBlockHandler.class,
            blockHandler = "handlerException")
    public CommonResult customerException() {
        return new CommonResult(200, "按资源名称限流测试OK === 自定义Handler");
    }

    // fallback负责运行时异常
    // blockHandler负责Sentinel控制台配置违规
    // 若blockHandler和fallbakc都进行了配置，则blockHandler的优先级大于fallback
    @GetMapping("/consumer/get/{id}")
    @SentinelResource(value = "payment/getId",
            fallback = "handlerFallback",
            blockHandler = "blockHandler")
    public CommonResult getPaymentById(@PathVariable("id") Long id) {
        CommonResult result = new CommonResult(200, "未发生错误，正常返回");
        if (id == 4) {
            throw  new IllegalArgumentException("IllegalArgumentException，非法参数异常。。。");
        }
        return result;
    }

    // fallback
    public CommonResult handlerFallback(Long id, Throwable throwable) {
        return new CommonResult(444, "兜底异常handlerFallback");
    }
    // blockHandler
    public CommonResult blockHandler(Long id, BlockException exception) {
        return new CommonResult(445,"blockHandler限流");
    }

    /////////////////////////////////////  服务异常处理方式 结束  ////////////////////////////////////////

    /////////////////////////////////////  服务降级 开始  ////////////////////////////////////////
    @GetMapping("/consumer/sentinel/rt")
    public String sentinel_rt() {
        String result = "服务降级 ==== 平均响应时间";
        log.info(result);
        try {
            // 暂停1秒钟
            TimeUnit.MILLISECONDS.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return result;
    }

    @GetMapping("/consumer/sentinel/exceptionRate")
    public String sentinel_exceptionRate() {
        String result = "服务降级 ==== 异常比例";
        log.info(result);
        int num = 10 / 0;
        return result;
    }

    @GetMapping("/consumer/sentinel/exceptionNum")
    public String sentinel_exceptionNum() {
        String result = "服务降级 ==== 异常数目";
        log.info(result);
        int num = 10 / 0;
        return result;
    }
    /////////////////////////////////////  服务降级 结束  ////////////////////////////////////////

    /////////////////////////////////////  服务限流 开始  ////////////////////////////////////////
    @GetMapping("/consumer/sentinel/qps/direct/quick")
    public String sentinel_qps_direct_quick() {
        String result = "服务限流 ==== QPS - 直接 - 快速失败";
        log.info(result);
        try {
            // 暂停1秒钟
            TimeUnit.MILLISECONDS.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return result;
    }

    @GetMapping("/consumer/sentinel/qps/direct/warmUp")
    public String sentinel_qps_direct_warmUp() {
        String result = "服务限流 ==== QPS - 直接 - warmUp";
        log.info(result);
        return result;
    }

    @GetMapping("/consumer/sentinel/qps/direct/queue")
    public String sentinel_qps_direct_queue() {
        String result = "服务限流 ==== QPS - 直接 - 排队等待";
        log.info(result);
        return result;
    }
    /////////////////////////////////////  服务限流 结束  ////////////////////////////////////////

    /////////////////////////////////////  热点参数限流 开始  ////////////////////////////////////////
    @GetMapping("/consumer/sentinel/hotkey")
    @SentinelResource(value = "consumer/sentinel/hotkey",blockHandler = "handler_hotkey")
    public String sentinel_hotkey(@RequestParam(value = "p1",required = false) String p1,
                                  @RequestParam(value = "p2",required = false) String p2) {
        String result = "热点参数限流 ====    p1="+p1 +"    p2="+p2;
        log.info(result);
        return result;
    }
    public String handler_hotkey(String p1, String p2, BlockException exception) {
        String result = "热点参数限流 ==== handler   p1="+p1 +"    p2="+p2;
        log.info(result);
        return result;
    }
    /////////////////////////////////////  热点参数限流 结束  ////////////////////////////////////////

}
